¿Cómo y dónde se producen los accidentes en Madrid?

Autores/as

Gema Fernández-Avilés (Gema.FAviles@uclm.es)

Isidro Hidalgo (Isidro.Hidalgo@uclm.es)

Fecha de publicación

20 de enero de 2025

Nota

Los datos que se utilizan en esta historia están disponibles en el paquete CDR que puede instalarse con el siguiente comando (se comprueba si no lo está):

if (!require(CDR)){
  if (!require(remotes)) {install.packages("remotes")}
  remotes::install_github("cdr-book/CDR")
  }

Accidentes de tráfico en la Ciudad de Madrid registrados por Policía Municipal con víctimas y/o daños al patrimonio en el 2020. Los datos se han descargado del Portal de datos abiertos del Ayuntamiento de Madrid.)

1 Cómo y dónde se producen los accidentes en Madrid

Esta mañana estaba tan tranquilo en mi oficina (trabajo en el distrito de Chamartín para el Ayuntamiento) y me sueltan de repente: “el jefe quiere verte”. Lo primero que he pensado es que me echaban, como soy un poco “cansa almas”… Pero no, entro en el despacho del jefe… ¡Y allí está Almeida! Que ha oído que he hecho un curso de visualización en la UCLM y me he convertido en un crack de la visualización. Yo no sabía donde meterme, pero he mantenido perfectamente la compostura, como un profesional.

Así que ya me ha ido contando que está muy preocupado con los accidentes y quiere analizar el tema, para buscar soluciones. Que me agradecería mucho si encontramos dónde está el problema, para bajar el número y gravedad de los accidentes en la ciudad. El problema, me dice, es que solo me puede facilitar los datos del año 2020. Ya le he avisado de que es un año muy particular, por el estado de alarma, pero algo sacaremos…

2 Entender el contexto

Cómo definir el propósito y la audiencia de tu análisis

¿Qué le interesa al alcalde? Bajar la tasa de accidentes. Pero desde el punto de vista de la visualización, está claro que va a necesitar información georreferenciada, por lo que haremos mapas. Por otro lado, seguro que la dimensión es importante, porque no es lo mismo Madrid en agosto que un día de lluvia en calendario escolar…

En cualquier caso, lo primero es hacer un análisis exploratorio para ver si hay algo raro en los datos y analizar mínimamente las variables de interés. Y después, le vamos a preparar los gráficos necesarios para aportarle conocimiento sobre los accidentes en la ciudad.

3 Elegir una visualización adecuada

Selección de gráficos y visualizaciones que mejor representen tus datos.

3.1 Almeida quiere saber cómo y dónde se producen los accidentes en Madrid

Ejercicio 1 ¿Dónde se han producido los accidentes de tráfico en Madrid en el 2020?

data(accidentes2020_data)

ggplot(data = accidentes2020_data,
       aes(x = coordenada_x_utm, y = coordenada_y_utm)) + 
  geom_point() +
  coord_fixed()

3.2 El desorden es tu enemigo

Deja mucho que desear, ¿verdad?: no tenemos información, solo unos datos representados en un gráfico. Con muy poco, tirando de estética (reduciendo la dimensión de los puntos para que se vea el fondo) y alguna referencia geográfica (en forma de mapa de carreteras), veremos cómo se reduce la carga cognitiva:

accidentes2020_sf <- st_as_sf(accidentes2020_data,
  coords = c("coordenada_x_utm", "coordenada_y_utm"),
  crs = 25830 # proyección ETRS89/ UTM zone 30N. Área de uso: Europa  
  )  

madrid <- esp_get_munic(munic = "^Madrid$") |>
  st_transform(25830) 

# descarga imagen de un de mapa estático de las carreteras de Madrid
tile <- esp_getTiles(madrid, "IDErioja", zoommin = 2)  

ggplot() +
  geom_spatraster_rgb(data = tile) +
  geom_sf(data = accidentes2020_sf, 
    col = "blue", size = 0.05, alpha = 0.3) +
  coord_sf(expand = FALSE) +
  labs(title = "¿Dónde se producen los accidentes de tráfico en Madrid?")

¡Esto ya es otra cosa! Apreciamos, lógicamente, la concentración de accidentes en el centro de la ciudad y, especialmente, en las arterias principales.

3.3 El cuándo

Además, como hemos comentado, tenemos conocimiento a priori sobre la influencia de la fecha en el aumento de tráfico, por lo que probablemente encontremos alguna influencia de la dimensión temporal. Vamos a verlo…

Ejercicio 2 ¿Cuándo se han producido los accidentes?

ggplot(data = accidentes2020_data,
       aes(x = fecha, y = hora)) + 
  geom_point() +
  theme_minimal()

3.4 Eliminemos de nuevo el desorden

Vamos a separar la fecha y la hora, porque en ese gráfico no vemos casi nada…

# Convertir la columna 'fecha' a formato Date
accidentes2020_data$fecha <- as.Date(accidentes2020_data$fecha, format = "%d/%m/%Y")

accidentes2020_fecha <- accidentes2020_data |>
  select(fecha) |>
  group_by(fecha) |>
  mutate(n = n()) |>
  unique()

ggplot(data = accidentes2020_fecha,
       aes(x = fecha, y = n)) + 
  geom_line() +
  theme_minimal()

Como ya le advertimos al alcalde, el año 2020 no es bueno para sacar conclusiones. Ya le hemos pedido que nos facilite datos más amplios para poder proporcionarle una mejor visualización del número de accidentes por fecha, pero mientras tanto, nos tendremos que arreglar con lo que tenemos…

# Convertir la columna 'hora' a formato Date y extraer la hora del día
accidentes2020_data$hora_dia <- hour(as.POSIXct(accidentes2020_data$hora, format = "%H:%M:%S"))

# Contamos los accidentes por hora
accidentes2020_hora_dia <- accidentes2020_data |>
  select(hora_dia) |>
  group_by(hora_dia) |>
  mutate(n = n()) |>
  unique()

ggplot(data = accidentes2020_hora_dia,
       aes(x = hora_dia, y = n)) + 
  geom_line(linewidth = 1, color = "orange") +
  labs(title = "Número de accidentes según la franja horaria del día",
       subtitle = "Las 14 y las 19 horas presentan el mayor número de accidentes",
       x = "Hora del día", y = "Número de accidentes en la franja horaria") +
  scale_y_continuous(labels = function(x) {
    format(x,
      big.mark = ".", decimal.mark = ",", scientific = FALSE
    )
  }) +
  theme_minimal()

Es evidente que la hora punta a mediodía y en la salida del trabajo, a las 14 y las 19 horas del día son los 2 picos a vigilar. Pero este gráfico tiene un gran margen de mejora.

Ejercicio 3 ¿De qué tipo son los accidentes?

accidentes2020_data <- accidentes2020_data |>
  mutate_if(is.character, as.factor)

accidentes2020_data |>
  count(tipo_accidente) |>
  mutate(porcentaje = 100 * n / sum(n))
                  tipo_accidente     n porcentaje
                          <fctr> <int>      <num>
 1:                      Alcance  7294 22.4936010
 2:           Atropello a animal    75  0.2312887
 3:          Atropello a persona  2127  6.5593487
 4:                        Caída  2118  6.5315940
 5: Choque contra obstáculo fijo  4667 14.3923274
 6:             Colisión frontal   899  2.7723810
 7:      Colisión fronto-lateral  8081 24.9205909
 8:             Colisión lateral  4386 13.5257656
 9:            Colisión múltiple  2231  6.8800691
10:                Despeñamiento     2  0.0061677
11:                         Otro   251  0.7740463
12:        Solo salida de la vía   151  0.4656613
13:                       Vuelco   145  0.4471582

Las tablas también son elementos de visualización. En este caso, hay algo evidente que hacer, pero lo vamos a explicar con el siguiente gráfico:

3.5 El tipo de accidente

accidentes2020_data |>
  ggplot() +
  geom_bar(aes(y=tipo_accidente), fill = "orange", alpha = 0.6) +
  theme_bw()

¿Qué le falta a este gráfico?¿En qué se puede mejorar? Pues está muy claro: ordenar las categorías. Si no están ordenadas tardamos mucho en determinar, por ejemplo, cuál es la tercera, o la quinta… Únicamente la más importante es relativamente fácil de situar. Pero veamos cuando ordenamos las categorías:

ggplot(accidentes2020_data, aes(y = reorder(tipo_accidente,
                                            -tipo_accidente,
                                            length))) +
  geom_bar(fill = "orange", alpha = 0.6) +
  labs(title = "Tipos de accidente en Madrid durante el año 2020",
       subtitle = "Sobresalen la colisión fronto-lateral y el alcance",
       x = "Número de accidentes", y = "") +
  scale_x_continuous(labels = function(x) {
    format(x,
      big.mark = ".", decimal.mark = ",", scientific = FALSE
    )
  }) +
  theme_bw()

3.6 Visualizaciones específicas georreferenciadas

Una categoría especial, y que merece mucho la pena destacar, cuando tenemos información georreferenciada, son los mapas interactivos. Una de las librerías más populares para construirlos es ‘leaflet’, que usa los mapas de OpenStreetMap, permitiendo incluir los mapas físicos de ESRI.

accidentes2020_sf <- st_transform(accidentes2020_sf, crs = 4326)
accidentes2020_data$longitude <- st_coordinates(accidentes2020_sf)[, 1]
accidentes2020_data$latitude <- st_coordinates(accidentes2020_sf)[, 2]

leaflet(data = accidentes2020_data) |>
  addTiles() |>
  addCircleMarkers(lng = ~longitude, lat = ~latitude, 
                   radius = 1, color = "red", opacity = 0.5)  
#  addProviderTiles(providers$Esri.WorldImagery)

3.7 Piensa como un diseñador

Estas visualizaciones están muy bien pero… ¿y si pudiéramos aminorar la carga cognitiva del mapa interactivo? Una forma de hacerlo es usar agrupaciones. Veamos cómo hacerlo.

leaflet(data = accidentes2020_data) |>
  addTiles() |>
  addCircleMarkers(lng = ~longitude, lat = ~latitude, 
                   radius = 2, color = "red", opacity = 0.5, clusterOptions = markerClusterOptions())

Otra forma de visualizar que permite ‘leaflet’ son los mapas de calor:

leaflet(data = accidentes2020_data) |>
  addTiles() |>
  addHeatmap(lng = ~longitude, lat = ~latitude, blur = 50, max = 0.05)

Ejercicio 4 Esta visualización la podemos configurar con los parámetros. Es tu turno: juega con ellos y consigue una gradación e intensidad de colores a tu gusto.

leaflet(data = accidentes2020_data) |>
  addTiles() |>
  addHeatmap(lng = ~longitude, lat = ~latitude,
             blur = _____, max = _____)

4 Contar una historia

Cómo narrar una historia convincente con tus datos.

Hemos visto el planteamiento, en el que proporcionamos el contexto: el mismísimo alcalde de Madrid se ha enterado de nuestras excelentes capacidades y nos ha pedido ayuda…

El análisis exploratorio nos ha ido introduciendo en la trama, donde descubrimos que hay una fuerte dependencia de la hora del día y del lugar donde se produce el accidente.

Pero como siempre, lo más importante es el desenlace, donde le estamos dando al alcalde las conclusiones más interesantes, que podríamos resumir en un par de gráficos:

  • Con el gráfico de evolución del número de accidentes a lo largo del día va a saber que (es lógico) que en las 14 y 19 horas se producen el mayor número de accidentes.

  • Con un mapa interactivo (podemos elegir cuál nos proporciona la mejor visualización) le damos la posibilidad de mirar de forma dinámica qué zonas son las que necesitan más acciones de protección.

4.1 Para pensar:

Nosotros te hemos propuesto un par de visualizaciones, pero puede que no estés de acuerdo… ¿Qué visualizaciones utilizarías en el desenlace, para aportarle el mayor conocimiento a Almeida sobre los accidentes de tráfico de su ciudad?